#include "./commandManager.hpp"
#include "./baseCommand.hpp"

using namespace qbe::undoRedoT;

CommandManager::UndoRedoStateInspector::UndoRedoStateInspector(CommandManager* pCommandManager)
    : m_pCommandManager(pCommandManager), m_bUndoable(pCommandManager->CanUndo()), m_bRedoable(pCommandManager->CanRedo()) {}

CommandManager::UndoRedoStateInspector::~UndoRedoStateInspector() {
  if (m_bUndoable != m_pCommandManager->CanUndo() || m_bRedoable != m_pCommandManager->CanRedo()) {
    // std::stringstream ssData;
    // ssData << m_pCommandManager->CanUndo();
    // ssData << ',';
    // ssData << m_pCommandManager->CanRedo();
    // m_pCommandManager->Notify(NULL, EVENT_UNDOREDOSTATECHANGED, ssData);
  }
}

CommandManager::CommandManager() {}

CommandManager::~CommandManager() {
  // ClearAllCommands();
  for (auto pool : undo_redo_pools) {
    while (!pool->stackUndo.empty()) {
      delete pool->stackUndo.top();
      pool->stackUndo.pop();
    }

    while (!pool->stackRedo.empty()) {
      delete pool->stackRedo.top();
      pool->stackRedo.pop();
    }
  }
}

CommandManager* CommandManager::Instance() {
  static CommandManager* res = new CommandManager;
  return res;
}

bool CommandManager::CallCommand(BaseCommand* pCommand) {
  UndoRedoStateInspector si(this);

  if (pCommand) {
    if (pCommand->Execute()) {
      PushUndoCommand(pCommand);
      DeleteRedoCommands();
      return true;
    } else {
      delete pCommand;
    }
  }

  return false;
}

void CommandManager::ClearAllCommands() {
  UndoRedoStateInspector si(this);

  DeleteUndoCommands();
  DeleteRedoCommands();
}

void CommandManager::Undo() {
  UndoRedoStateInspector si(this);

  BaseCommand* pCommand = PopUndoCommand();
  if (pCommand) {
    if (pCommand->Unexecute()) {
      PushRedoCommand(pCommand);
    } else {
      delete pCommand;
    }
  }
}

void CommandManager::Redo() {
  UndoRedoStateInspector si(this);

  BaseCommand* pCommand = PopRedoCommand();
  if (pCommand) {
    if (pCommand->Execute()) {
      PushUndoCommand(pCommand);
    } else {
      delete pCommand;
    }
  }
}

bool CommandManager::CanUndo() const {
  return !stackUndo.empty();
}

bool CommandManager::CanRedo() const {
  return !stackRedo.empty();
}

// 限制大小
void CommandManager::limitStep(std::stack<BaseCommand*>& m_stack) {
  // 如果储存量大于上限
  if (m_stack.size() > max_step) {
    std::stack<BaseCommand*> temp;
    // 取出顶上最大限度条命令
    for (int i = 0; i < max_step; i++) {
      temp.push(m_stack.top());
      m_stack.pop();
    }
    // 释放其他命令
    while (!m_stack.empty()) {
      delete m_stack.top();
      m_stack.pop();
    }
    for (int i = 0; i < max_step; i++) {
      m_stack.push(temp.top());
      temp.pop();
    }
  }
}

void CommandManager::PushUndoCommand(BaseCommand* pCommand) {
  if (pCommand) {
    stackUndo.push(pCommand);
    limitStep(stackUndo);  // Undo同样限制大小
    is_change_saved = false;
  }
}

// 弹出一条Undo
BaseCommand* CommandManager::PopUndoCommand() {
  BaseCommand* pCommand = NULL;
  if (!stackUndo.empty()) {
    pCommand = stackUndo.top();
    stackUndo.pop();
  }
  return pCommand;
}

// 增加一条Redo指令
void CommandManager::PushRedoCommand(BaseCommand* pCommand) {
  if (pCommand) {
    stackRedo.push(pCommand);
    limitStep(stackRedo);  // 限制Redo
    is_change_saved = false;
  }
}

// 弹出一条Redo指令
BaseCommand* CommandManager::PopRedoCommand() {
  BaseCommand* pCommand = NULL;
  if (!stackRedo.empty()) {
    pCommand = stackRedo.top();
    stackRedo.pop();
  }
  return pCommand;
}

// 清空目前Undo
void CommandManager::DeleteUndoCommands() {
  while (!stackUndo.empty()) {
    delete stackUndo.top();
    stackUndo.pop();
  }
}

// 清空目前Redo
void CommandManager::DeleteRedoCommands() {
  while (!stackRedo.empty()) {
    delete stackRedo.top();
    stackRedo.pop();
  }
}

// 切换新的Undo Redo
void CommandManager::switchUndoRedo(unsigned index) {
  if (index == current_undo_redo_index)
    return;

  auto old_pool = undo_redo_pools[current_undo_redo_index];
  old_pool->stackUndo = stackUndo;
  old_pool->stackRedo = stackRedo;
  old_pool->is_change_saved = is_change_saved;

  current_undo_redo_index = index;
  auto pool = undo_redo_pools[index];
  stackUndo = pool->stackUndo;
  stackRedo = pool->stackRedo;
  is_change_saved = pool->is_change_saved;
}

// 创建新的Undo Rdo并切换
unsigned CommandManager::createUndoRedoPool() {
  undo_redo_pools.push_back(new UndoRedoPool);
  auto index = undo_redo_pools.size() - 1;
  switchUndoRedo(index);
  return index;
}

// 设置是否保存
void CommandManager::setChangeSaved(bool is_change_save, unsigned index) {
  is_change_saved = is_change_save;
  undo_redo_pools[index]->is_change_saved = is_change_save;
}

// 返回当前Undo Redo是否保存
bool CommandManager::getChangeSaved() {
  return is_change_saved;
}

// 获取当前的Undo Redo管理器
UndoRedoPool* CommandManager::getUndoRedoPool(unsigned index) {
  return undo_redo_pools[index];
}

BaseCommand* CommandManager::UndoCommand() {
  BaseCommand* pCommand = NULL;
  if (!stackUndo.empty()) {
    pCommand = stackUndo.top();
  }
  return pCommand;
}
BaseCommand* CommandManager::RedoCommand() {
  BaseCommand* pCommand = NULL;
  if (!stackRedo.empty()) {
    pCommand = stackRedo.top();
  }
  return pCommand;
}